class CourseController < ApplicationController
  before_filter :login_required, :only => [ :show, :enroll, :add_event, :list_own, :index, :list, :quit ]
  before_filter :admin_required, :only => [ :create, :new, :destroy, :enroll_list_student, :enroll_list_instructor ]
  before_filter :instructor_required, :only => [ :edit, :update ]

  # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
  verify :method => :post, :only => [ :destroy, :create, :update ],
         :redirect_to => { :action => :list }

  # Mismo que list
  def index
    list
    render :action => 'list'
  end

  # Enrola al usuario actual al curso con id ":id".
  # Le muestra una interfaz en la que le pregunta si se quiere enrolar al curso,
  # si selecciona que sí hace un post a este mismo action. Si no, se regresa a
  # la lista.
  def enroll
    if request.xhr?
      # ---- Para AJAX ---
      begin
        course = Course.find(params[:id])
        user = User.find(params[:user_id])
        if user.courses.include?(course)
          render :update do |page|
            page.replace_html "status#{params[:user_id]}", '<span style="color:red">Ya esta en el curso.</span>'
          end
          return
        end
        user.courses << course
        render :update do |page|
          page.replace_html "status#{params[:user_id]}", "<span style=\"color:green\">Exit&oacute;samente a&ntilde;adido #{user.login} al curso #{course.name}</span>"
          page.hide "entry#{params[:user_id]}"
        end
      rescue ActiveRecord::RecordNotFound
        render :update do |page|
          page.replace_html "status#{:user_id}", '<span style="color:red">Error con el usuario o el curso.</span>'
        end
        return
      end

    else
      # --- NORMAL ---
      if params[:id].nil?
        redirect_to :action => 'index'
        return
      end

      @course = Course.find(params[:id])
      if @course.name == "Eventos Globales" and self.is_student?
        flash[:error]="No te puedes unir a este curso."
        redirect_to :action => 'index'
      end

      user = self.current_user
      if user.courses.include?(@course)
        flash[:error] = "Ya eres parte de este curso!"
        redirect_to :action => 'index'
        return
      end

      return if request.get?
      user.courses << @course


      flash[:notice] = "Exitosamente a&ntilde;adido al curso #{@course.name}"
      redirect_to :action => 'index'
    end
  rescue ActiveRecord::RecordNotFound
    flash[:error] = "No puedo encontrar curso con id #{params[:id]}"
    redirect_to :action => 'index'
  rescue Exception => e
    flash[:error] = "Error: "+e.message + "<br>Backtrace: "+e.backtrace.join("<br>")
    redirect_to :action => 'index'
  end


  # Lista los cursos disponibles. Muestra por cada uno:
  #  Nombre del curso
  #  Descripcion (truncada a 45 caracteres)
  #  Fecha de fin de curso.
  def list
    @title = "Cursos"
    @course_pages, @all_courses = paginate :all_courses, :singular_name => 'course', :per_page => 10, :order => 'end_date DESC'
  end

  # Entra al curso dado, segun el rol del usuario actual es lo que muestra.
  def show
    @course = Course.find(params[:id])
    @in_there = self.current_user.courses.include?(@course)

    # El curso no ha caducado aún...
    if @course.end_date.nil? or Time.now < @course.end_date or @in_there or self.is_admin?
      redirect_to(:action => 'enroll', :id => @course) and return if not @in_there and not self.is_admin?

      now = Time.now
      # Todos los eventos siguientes.
      @events = @course.events.select { |e| e.expire_date > now }.sort { |a,b| a.expire_date <=> b.expire_date }
      # Todas las tareas.
      @assignments = @course.assignments
      # Todos los usuarios.
      @users = @course.users
      if self.is_instructor? or self.is_admin?
        # Calcular el promedio de cada estudiante en el curso.
        tmp = @course.assignments.map { |a|
          a.assignment_answers.map { |n|
            [ n.user, ( n.grade || 0.0 ) * a.weight ]
          }
        }
        @average = {}
        tmp.each { |t|
          t.each { |a|
            if @average[ a[0] ]
              @average[ a[0] ] += a[1]
            else
              @average[ a[0] ] = a[1]
            end
          }
        }
      else
        # Revisar que tareas he contestado y cuales no.
        @answered = {}
        @assignments.each { |a|
          for ans in a.assignment_answers
            if ans.user = current_user
              @answered[a] = true
              break
            end
          end
        }
      end
      # Sólo necesitamos las tareas que no han expirado.
      @assignments = @assignments.select { |e| e.expire_date > now }.sort { |a,b| a.expire_date <=> b.expire_date }
      render(:file => 'course/show_instructor', :use_full_path => true, :layout => true)  if self.is_instructor? or self.is_admin?
      render(:file => 'course/show_student', :use_full_path => true, :layout => true) if self.is_student?
    else
      flash[:notice] = "El curso ya termin&oacute;."
      redirect_to(:controller => 'account', :action => 'index')
    end
  rescue ActiveRecord::RecordNotFound
    flash[:error] = "No puedo encontrar curso con id #{params[:id]}"
    redirect_to :action => 'index'
  end

  # Crea un nuevo curso
  def new
    @course = Course.new
  end

  # Guarda el curso nuevo.
  def create
    redirect_to(:action => 'new') and return unless request.post?
    @course = Course.new(params[:course])
    @course.creator = self.current_user
    if @course.save
      flash[:notice] = 'Curso creado existosamente.'
      redirect_to :action => 'list'
    else
      render :action => 'new'
    end
  end

  # Muestra lo necesario para editar a un curso
  def edit
    @course = Course.find(params[:id])
  end

  # Hace la edición del curso en si.
  def update
    @course = Course.find(params[:id])
    if @course.update_attributes(params[:course])
      flash[:notice] = 'Course was successfully updated.'
      redirect_to :action => 'show', :id => @course
    else
      render :action => 'edit'
    end
  end

  # Borra un curso.
  def destroy
    curso = Course.find(params[:id])
    curso.destroy unless curso.name == "Eventos Globales"
    redirect_to :action => 'list'
  rescue
    flash[:error] = "Error borrando el curso con id = #{params[:id]}".
    redirect_to :action => 'list'
  end

  # Muestra una lista de tus propios cursos
  def list_own
    @course_pages = Paginator.new self, @side_courses.size , 10, params[:page]
    @all_courses = @side_courses[@course_pages.current.offset..@course_pages.current.last_item]
    render :action => 'list'
  end

  # Saca a un usuario del curso.
  def quit
    # * Sólo acepta por POST
    # * Saca al usuario actual del curso :id
    # * Si es administrador, saca al usuario :user_id del curso :id.
    # 1. Quita todas las Respuestas que haya dado el usuario en este curso.
    # 2. Quita la relacion course_user correspondiente.
    # 3. Redirije a '/'
    if not request.post?
      redirect_to '/'
      return
    end

    if params[:id].nil?
      flash[:error] = "No conozco el grupo nil."
      redirect_to '/'
      return
    end

    if params[:user_id] and not self.is_admin?
      access_denied
      return
    end

    course = nil
    begin
      course = Course.find(params[:id])
    rescue ActiveRecord::RecordNotFound
      flash[:error] = "No conozco el grupo #{params[:id]}."
      redirect_to '/'
      return
    end

    user = nil
    if params[:user_id]
      begin
        user = User.find(params[:user_id])
      rescue ActiveRecord::RecordNotFound
        flash[:error] = "No conozco al usuario #{params[:user_id]}"
        redirect_to '/'
        return
      end
    else
      user = self.current_user
    end
    if not user.courses.include?(course)
      flash[:error] = "El usuario no está en el curso!"
      redirect_to '/'
      return
    end
    user.courses.delete(course)

    # Borrar todas las respuestas a las tareas.
    AssignmentAnswer.destroy_all([ "user_id = ? AND assignment_id IN (?)", user.id, course.assignments.map { |m| m.id } ])


    flash[:notice] = "El usuario #{user.login} ya no está en el curso #{course.name}."
    redirect_to '/'
  rescue
    flash[:error] = $! #Mostrar mensaje de la excepción.
    redirect_to '/'
  end

  # Lista todos los estudiantes NO enrolados en el curso :id.
  def enroll_list_student
    # * Sólo para administradores
    # * El :id es el ID del curso.
    # 1. Muestra una lista de todos los estudiantes que NO están enrolados en
    #       el curso, y le permite dar CLICK en cada uno de ellos para
    #       enrolarlos en el curso. Usa AJAX.

    @course = Course.find(params[:id])
    @students = User.find_by_sql(["SELECT u.* FROM users u WHERE u.kind = ? AND NOT u.id IN (SELECT u.id FROM users u, courses_users cu WHERE u.id = cu.user_id AND cu.course_id = ?)",
                                 'Student', @course])
  end

  # Igual, para instructores.
  def enroll_list_instructor
    # * Sólo para administradores
    # * El :id es el ID del curso.
    # 1. Muestra una lista de todos los estudiantes que NO están enrolados en
    #       el curso, y le permite dar CLICK en cada uno de ellos para
    #       enrolarlos en el curso. Usa AJAX.

    @course = Course.find(params[:id])
    # Variable con un mal nombre...
    @students = User.find_by_sql(["SELECT u.* FROM users u WHERE u.kind = ? AND NOT u.id IN (SELECT u.id FROM users u, courses_users cu WHERE u.id = cu.user_id AND cu.course_id = ?)",
                                 'Instructor', @course])
    render :action => 'enroll_list_student'
  end
end
